package antoine.ear;

import javax.sound.midi.Instrument;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;

import antoine.ear.exo.Exo;
import antoine.ear.keyboard.Keyboard;

public class Player   {
	
	private Sequencer	sm_sequencer = null;
	private Synthesizer	sm_synthesizer = null;
	public static Keyboard keyboard;
	
	private Exo exo;
	
	public Player(Exo exo) {
		this.exo = exo;
	}
	

	public void play(){
		try {
			Sequence sequence = exo.getSequence();

			if (sm_sequencer!=null){
				sm_sequencer.close();
			}
			
			
			// Request of the defaut sequencer
			sm_sequencer = MidiSystem.getSequencer();
			if (sm_sequencer == null) {
				System.exit(1);
			}

			/*
			 *	There is a bug in the Sun jdk1.3/1.4.
			 *	It prevents correct termination of the VM.
			 *	So we have to exit ourselves.
			 *	To accomplish this, we register a Listener to the Sequencer.
			 *	It is called when there are "meta" events. Meta event
			 *	47 is end of track.
			 *
			 *	Thanks to Espen Riskedal for finding this trick.
			 */
			sm_sequencer.addMetaEventListener(new MetaEventListener() {
					public void meta(MetaMessage event)	{
						if (event.getType() == 47) {
							sm_sequencer.close();
							if (sm_synthesizer != null)	{
								sm_synthesizer.close();
							}
						}
						else if (event.getType() == Exo.ACTIVATENOTE) {
							byte[] tab = event.getData();
							keyboard.activateNote(tab[0], true);
						}
						else if (event.getType() == Exo.DESACTIVATENOTE) {
							byte[] tab = event.getData();
							keyboard.activateNote(tab[0], false);
						}
						else if (event.getType() == Exo.CLEAR) {
							keyboard.clearKeyb();
						}
					}
				});

			sm_sequencer.open();
			sm_sequencer.setSequence(sequence);
		} catch (Exception e1) {
			e1.printStackTrace();
			System.exit(-1);
		}

		if (! (sm_sequencer instanceof Synthesizer)){
			/*
			 *	We try to get the default synthesizer, open()
			 *	it and chain it to the sequencer with a
			 *	Transmitter-Receiver pair.
			 */
			try	{
				sm_synthesizer = MidiSystem.getSynthesizer();
				sm_synthesizer.open();
				Receiver	synthReceiver = sm_synthesizer.getReceiver();
				Transmitter	seqTransmitter = sm_sequencer.getTransmitter();
				seqTransmitter.setReceiver(synthReceiver);
				//sm_synthesizer.loadAllInstruments(sm_synthesizer.getDefaultSoundbank());
				//sm_synthesizer.getChannels()[0].programChange(68);
			}
			catch (MidiUnavailableException e)	{
				e.printStackTrace();
			}
		}
	
		sm_sequencer.start();
	}

	public Exo getExo() {
		return exo;
	}

	public void setExo(Exo exo) {
		this.exo = exo;
	}
	
	public void stop(){
		sm_sequencer.stop();
	}
	
	public boolean isPlaying(){
		return sm_sequencer.isRunning();
	}
	
	public void init(){
		try {
			// Request of the defaut sequencer
			sm_sequencer = MidiSystem.getSequencer();
			if (sm_sequencer == null) {
				System.exit(1);
			}
			
			sm_sequencer.open();
		} catch (MidiUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
